from rest_framework import viewsets, filters, permissions, status
from rest_framework.decorators import action
from rest_framework.response import Response
from django_filters.rest_framework import DjangoFilterBackend
from .models import AITemplate, RequirementAnalysis, AIGenerationLog, GeneratedTestCaseMapping
from .serializers import (
    AITemplateSerializer, AITemplateCreateSerializer, 
    RequirementAnalysisSerializer, RequirementAnalysisCreateSerializer,
    AIGenerationLogSerializer, AIGenerationLogCreateSerializer,
    GeneratedTestCaseMappingSerializer, FileUploadSerializer,
    GenerateTestCaseSerializer, GenerateMindmapSerializer
)
import openai
import pandas as pd
from django.http import HttpResponse
import io
import time
from datetime import datetime
import os
import docx
import requests
import json

"""
AI集成模块视图和API实现

作者: heruopu
© 2025 Heruopu. All rights reserved.
"""

import os
import json
import time
import logging
from typing import Dict, List, Any, Optional
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
from django.shortcuts import render
from django.http import JsonResponse
from django.views import View
from django.conf import settings
from django.db import transaction
from django.db.models import Q

# AI模型集成基类
class BaseAIModelAPI:
    """AI模型API基础封装"""
    def __init__(self, api_key=None, api_base=None):
        self.api_key = api_key
        self.api_base = api_base
        self.client = None
        self.model_name = ""
        self.configure_client()
    
    def configure_client(self):
        """配置API客户端"""
        raise NotImplementedError("子类必须实现configure_client方法")
    
    def analyze_requirement(self, content, project_type=None):
        """分析需求文档"""
        raise NotImplementedError("子类必须实现analyze_requirement方法")
    
    def generate_test_cases(self, requirement_content, project_type=None, template=None):
        """生成测试用例"""
        raise NotImplementedError("子类必须实现generate_test_cases方法")

# DeepSeek R1模型集成
class DeepSeekAPI(BaseAIModelAPI):
    """DeepSeek R1模型API封装"""
    def __init__(self, api_key=None, api_base=None):
        self.model_name = "deepseek-r1"
        super().__init__(api_key, api_base)
        
    def configure_client(self):
        # 配置DeepSeek API - 兼容旧版本OpenAI库
        # 注意：实际使用时需要从环境变量或配置文件中读取API密钥
        if not self.api_key:
            self.api_key = os.environ.get('DEEPSEEK_API_KEY', '')
        if not self.api_base:
            self.api_base = os.environ.get('DEEPSEEK_API_BASE', 'https://api.deepseek.com')
        
        # 检查API密钥是否为空或占位符
        if not self.api_key or self.api_key == 'your-api-key':
            raise ValueError("DeepSeek API密钥未配置，请在系统设置中配置有效的API密钥")
        
        # 使用旧版本OpenAI API语法
        import openai
        openai.api_key = self.api_key
        if self.api_base:
            openai.api_base = self.api_base
        
        # 优化连接配置，设置连接池和长连接参数
        session = requests.Session()
        
        # 配置连接池，提高并发请求处理能力
        adapter = requests.adapters.HTTPAdapter(
            pool_connections=20,  # 增加连接池中的连接数
            pool_maxsize=30,      # 增加最大连接数
            pool_block=False      # 是否阻塞等待连接
        )
        session.mount('http://', adapter)
        session.mount('https://', adapter)
        
        # 设置优化的超时时间（180000毫秒=3分钟），减少等待时间提高响应速度
        session.timeout = 180000
        
        # 配置优化的重试策略
        from urllib3.util.retry import Retry
        retry_strategy = Retry(
            total=2,              # 减少重试次数以避免长时间等待
            backoff_factor=0.3,   # 加快重试间隔增长速度
            status_forcelist=[429, 500, 502, 503, 504],
            allowed_methods=['HEAD', 'GET', 'PUT', 'POST', 'DELETE', 'OPTIONS', 'TRACE']
        )
        retry_adapter = requests.adapters.HTTPAdapter(max_retries=retry_strategy)
        session.mount('http://', retry_adapter)
        session.mount('https://', retry_adapter)
        
        openai.requestssession = session
        self.client = openai
    
    def analyze_requirement(self, content, project_type=None):
        """分析需求文档 - 使用优化版提示词"""
        # 使用优化版提示词，确保分析结果符合规范但更加简洁高效
        prompt = f"""你是专业的测试需求分析师和测试用例设计师，目标是快速、高效地分析需求并生成测试用例。

任务：基于需求文档，快速完成以下工作：
1. 需求拆解：提取需求核心要素（ID、名称、功能点）
2. 测试用例生成：每个功能点生成1-2个关键用例（正常+异常场景）

输出格式要求（使用Markdown）：
# 需求分析总结
## 1. 需求拆解
- **模块1**: 简要描述
  - **功能点1.1**: 描述
  - **功能点1.2**: 描述
- **模块2**: 简要描述
  ...

## 2. 测试用例集
| 用例ID | 关联需求ID | 用例名称 | 测试类型 | 测试用例类型 | 前置条件 | 测试步骤 | 预期结果 | 测试数据 | 用例设计方法 | 优先级 |
|--------|------------|----------|----------|--------------|----------|----------|----------|----------|--------------|--------|
| TC-001 | REQ-001    | 示例用例 | 功能测试 | 正常场景     | 系统登录 | 1.步骤1<br>2.步骤2 | 结果1<br>结果2 | 数据1   | 等价类划分   | 高     |

## 3. 用例设计说明
- 覆盖范围：覆盖所有主要功能点
- 未覆盖场景：如依赖外部系统的功能
- 测试类型分布：功能测试为主，关键安全点补充安全测试
- 核心设计方法：等价类、边界值、错误推测法

需求文档内容：
{content}

{'' if not project_type else f'注意：这是一个{project_type}类型的项目，请结合项目类型特点进行分析。'}

请保持输出简洁明了，重点突出，避免不必要的冗长描述，优先确保分析速度和结果实用性。
"""
        
        try:
            # 使用旧版本OpenAI API语法调用chat completion
            response = self.client.ChatCompletion.create(
                model="deepseek-chat",
                messages=[
                    {"role": "system", "content": "你是一个专业的测试需求分析师和测试用例设计师。"},
                    {"role": "user", "content": prompt}
                ],
                max_tokens=4000,  # 增加token数量以容纳更详细的分析结果
                temperature=0.7
            )
            return response['choices'][0]['message']['content']
        except Exception as e:
            error_msg = str(e)
            # 识别API密钥相关的错误
            if 'API key' in error_msg or 'api_key' in error_msg.lower() or 'your-api-key' in error_msg:
                raise Exception(f"API密钥配置错误: {error_msg}")
            elif 'timeout' in error_msg.lower():
                raise TimeoutError(f"DeepSeek API请求超时: {error_msg}")
            else:
                raise Exception(f"需求分析失败: {error_msg}")
    
    def generate_test_cases(self, requirement_content, project_type=None, template=None):
        """生成测试用例"""
        if template:
            prompt = template.replace('{{requirement}}', requirement_content)
        else:
            prompt = f"""你是一个专业的测试用例设计师，请根据以下需求生成测试用例：

需求内容：
{requirement_content}

请按照以下JSON格式生成测试用例，确保JSON格式正确，不要包含其他无关内容：
[
    {{
        "case_id": "用例ID",
        "title": "用例标题",
        "description": "用例描述",
        "precondition": "前置条件",
        "steps": "测试步骤（每行一个步骤）",
        "expected_result": "预期结果",
        "priority": "优先级（blocker/critical/high/medium/low）",
        "test_method": "用例设计方法（equivalence/boundary/decision_table/state_transition/use_case/error_guessing/scenario/other）",
        "module": "所属模块"
    }}
]

{'' if not project_type else f'注意：这是一个{project_type}类型的项目，请结合项目类型特点进行测试用例设计。'}
"""
        
        try:
            # 使用旧版本OpenAI API语法调用chat completion
            response = self.client.ChatCompletion.create(
                model="deepseek-chat",
                messages=[
                    {"role": "system", "content": "你是一个专业的测试用例设计师。"},
                    {"role": "user", "content": prompt}
                ],
                max_tokens=4000,
                temperature=0.7
            )
            return response['choices'][0]['message']['content']
        except Exception as e:
            error_msg = str(e)
            if 'API key' in error_msg or 'api_key' in error_msg.lower() or 'your-api-key' in error_msg:
                raise Exception(f"API密钥配置错误: {error_msg}")
            elif 'timeout' in error_msg.lower():
                raise TimeoutError(f"DeepSeek API请求超时: {error_msg}")
            else:
                raise Exception(f"用例生成失败: {error_msg}")

class AITemplateViewSet(viewsets.ModelViewSet):
    """AI提示词模板视图集"""
    queryset = AITemplate.objects.all().order_by('-created_at')
    serializer_class = AITemplateSerializer
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ['project_type', 'is_default']
    search_fields = ['name', 'description', 'content']
    ordering_fields = ['created_at', 'updated_at', 'name']
    permission_classes = [permissions.AllowAny]
    
    def get_serializer_class(self):
        """根据操作选择合适的序列化器"""
        if self.action == 'create':
            return AITemplateCreateSerializer
        return AITemplateSerializer
    
    @action(detail=False, methods=['get'], url_path='default-templates')
    def default_templates(self, request):
        """获取默认模板"""
        templates = AITemplate.objects.filter(is_default=True)
        serializer = AITemplateSerializer(templates, many=True)
        return Response(serializer.data)

class RequirementAnalysisViewSet(viewsets.ModelViewSet):
    """需求分析视图集"""
    queryset = RequirementAnalysis.objects.all().order_by('-created_at')
    serializer_class = RequirementAnalysisSerializer
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ['project', 'version', 'document_type']
    search_fields = ['document_name', 'analysis_result']
    ordering_fields = ['created_at', 'updated_at', 'modules_count', 'requirements_count']
    permission_classes = [permissions.AllowAny]
    
    def get_serializer_class(self):
        """根据操作选择合适的序列化器"""
        if self.action == 'create':
            return RequirementAnalysisCreateSerializer
        return RequirementAnalysisSerializer
    
    @action(detail=False, methods=['post'], url_path='upload-file')
    def upload_file(self, request):
        """上传需求文档并分析"""
        print("=== 接收文件上传请求 ===")
        print(f"请求数据：{dict(request.data)}")
        print(f"文件是否存在：{'file' in request.FILES}")
        print(f"project参数：{request.data.get('project')}")
        print(f"version参数：{request.data.get('version')}")
        
        serializer = FileUploadSerializer(data=request.data)
        if serializer.is_valid():
            print("序列化器验证通过")
            file = serializer.validated_data['file']
            project = serializer.validated_data['project']
            version = serializer.validated_data.get('version')
            print(f"验证后的项目：{project.id}, {project.name}")
            print(f"验证后的版本：{version.id if version else '无'}")
            
            # 读取文件内容
            content = ""
            try:
                if file.name.endswith('.docx'):
                    doc = docx.Document(file)
                    for para in doc.paragraphs:
                        content += para.text + '\n'
                elif file.name.endswith('.txt'):
                    content = file.read().decode('utf-8')
                elif file.name.endswith('.md'):
                    content = file.read().decode('utf-8')
                else:
                    return Response({'status': 'error', 'message': '不支持的文件格式'}, status=status.HTTP_400_BAD_REQUEST)
            except Exception as e:
                print(f"文件读取错误: {str(e)}")
                return Response({'status': 'error', 'message': f'文件读取失败: {str(e)}'}, status=status.HTTP_400_BAD_REQUEST)
            
            # 检查文档内容是否为空
            if not content.strip():
                return Response({'status': 'error', 'message': '文档内容为空，请上传有效的需求文档', 'error_type': 'empty_content'}, status=status.HTTP_400_BAD_REQUEST)
            
            # 使用DeepSeek API分析需求
            try:
                # 从请求中获取API配置信息
                api_key = request.data.get('api_key', '')
                api_base = request.data.get('api_base', '')
                model_type = request.data.get('model_type', 'deepseek-r1')
                
                print(f"接收到的API配置 - model_type: {model_type}, api_key: {'已配置' if api_key else '未配置'}, api_base: {api_base or '默认'}")
                
                # 根据模型类型创建相应的API实例
                if model_type == 'deepseek-r1':
                    deepseek_api = DeepSeekAPI(api_key=api_key, api_base=api_base)
                else:
                    # 如果是其他模型，这里可以扩展更多模型的支持
                    deepseek_api = DeepSeekAPI(api_key=api_key, api_base=api_base)
                    
                project_type = project.get_project_type_display()
                analysis_result = deepseek_api.analyze_requirement(content, project_type)
                
                # 解析分析结果，计算模块和需求数量
                # 改进模块数量计算：更精确地识别真正的模块数量
                modules_count = 0
                requirements_count = 0
                
                # 尝试多种可能的模块拆解标记格式
                module_markers = ['2. 模块拆解：', '2. 模块拆解', '### 2. 模块拆解：', '### 2. 模块拆解']
                module_section_start = -1
                
                # 寻找任意一种匹配的标记
                for marker in module_markers:
                    pos = analysis_result.find(marker)
                    if pos != -1:
                        module_section_start = pos
                        break
                
                if module_section_start != -1:
                    # 从模块拆解开始，找到下一部分开始的位置
                    next_section_markers = ['3. 需求点分析：', '3. 需求点分析', '### 3. 需求点分析：', '### 3. 需求点分析']
                    next_section_start = -1
                    
                    # 寻找任意一种匹配的下一部分标记
                    for marker in next_section_markers:
                        pos = analysis_result.find(marker, module_section_start)
                        if pos != -1:
                            next_section_start = pos
                            break
                    
                    # 如果没找到，就取到文本末尾
                    module_content = analysis_result[module_section_start:next_section_start] if next_section_start != -1 else analysis_result[module_section_start:]
                    
                    # 精确计算模块数量：只计算以- **或-开头的顶级模块列表项
                    # 但不计算子级列表项（如模块下的具体功能点）
                    module_lines = module_content.split('\n')
                    for line in module_lines:
                        stripped_line = line.strip()
                        # 只计算以- **或-开头的顶级模块列表项
                        if stripped_line.startswith('- **') or stripped_line.startswith('- ') and not stripped_line.startswith('-  '):
                            modules_count += 1
                
                # 如果改进后的计算没有结果，回退到原来的计算方式
                if modules_count == 0:
                    modules_count = analysis_result.count('模块拆解：') + analysis_result.count('模块：') + analysis_result.count('模块拆解') + analysis_result.count('模块')
                
                # 精确计算需求数量
                requirement_markers = ['3. 需求点分析：', '3. 需求点分析', '### 3. 需求点分析：', '### 3. 需求点分析']
                requirement_section_start = -1
                
                for marker in requirement_markers:
                    pos = analysis_result.find(marker)
                    if pos != -1:
                        requirement_section_start = pos
                        break
                
                if requirement_section_start != -1:
                    # 获取需求分析部分的内容
                    requirement_content = analysis_result[requirement_section_start:]
                    requirement_lines = requirement_content.split('\n')
                    for line in requirement_lines:
                        stripped_line = line.strip()
                        # 只计算以- **或-开头的顶级需求列表项
                        if stripped_line.startswith('- **') or stripped_line.startswith('- ') and not stripped_line.startswith('-  '):
                            requirements_count += 1
                
                # 如果改进后的计算没有结果，回退到合理的默认值
                if requirements_count == 0:
                    requirements_count = 5  # 设置一个合理的默认值
                
                # 保存分析结果
                requirement_analysis = RequirementAnalysis.objects.create(
                    project=project,
                    version=version,
                    original_content=content,
                    analysis_result=analysis_result,
                    modules_count=modules_count,
                    requirements_count=requirements_count,
                    analyzed_by=request.data.get('analyzed_by', ''),
                    document_name=file.name,
                    document_type=file.content_type
                )
                
                return Response({
                    'status': 'success',
                    'message': '需求分析成功',
                    'data': {
                        'id': requirement_analysis.id,
                        'analysis_result': analysis_result,
                        'modules_count': modules_count,
                        'requirements_count': requirements_count
                    }
                })
            except Exception as e:
                error_msg = str(e)
                print(f"AI分析错误: {error_msg}")
                # 更精确地识别API密钥错误
                error_type = 'api_key_error' if 'API密钥配置错误' in error_msg else 'analysis_failure'
                return Response({'status': 'error', 'message': error_msg, 'error_type': error_type}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        else:
            print(f"序列化器验证失败: {serializer.errors}")
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class AIGenerationLogViewSet(viewsets.ModelViewSet):
    """AI生成日志视图集"""
    queryset = AIGenerationLog.objects.all().order_by('-created_at')
    serializer_class = AIGenerationLogSerializer
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ['project', 'version', 'is_success', 'ai_model']
    search_fields = ['prompt', 'error_message']
    ordering_fields = ['created_at', 'updated_at', 'generation_time']
    permission_classes = [permissions.AllowAny]
    
    def get_serializer_class(self):
        """根据操作选择合适的序列化器"""
        if self.action == 'create':
            return AIGenerationLogCreateSerializer
        return AIGenerationLogSerializer

class GeneratedTestCaseMappingViewSet(viewsets.ModelViewSet):
    """生成用例映射视图集"""
    queryset = GeneratedTestCaseMapping.objects.all()
    serializer_class = GeneratedTestCaseMappingSerializer
    filter_backends = [DjangoFilterBackend, filters.OrderingFilter]
    filterset_fields = ['generation_log', 'is_approved']
    ordering_fields = ['id']
    permission_classes = [permissions.AllowAny]

class AIServiceViewSet(viewsets.ViewSet):
    """AI服务视图集"""
    permission_classes = [permissions.AllowAny]
    
    @action(detail=False, methods=['get'], url_path='get-ai-generated-cases')
    def get_ai_generated_cases(self, request):
        """获取所有AI生成的测试用例信息"""
        # 获取所有AI生成的测试用例映射
        ai_generated_mappings = GeneratedTestCaseMapping.objects.all()
        
        # 提取测试用例ID列表
        case_ids = [mapping.test_case.id for mapping in ai_generated_mappings]
        
        # 返回数据：包含用例ID列表和总数
        return Response({
            'case_ids': case_ids,
            'count': len(case_ids)
        })
        
    @action(detail=False, methods=['post'], url_path='generate-mindmap')
    def generate_mindmap(self, request):
        """生成思维导图"""
        print("=== 接收思维导图生成请求 ===")
        print(f"请求路径: {request.path}")
        print(f"请求方法: {request.method}")
        
        # 验证请求数据
        serializer = GenerateMindmapSerializer(data=request.data)
        if serializer.is_valid():
            print("请求数据验证通过")
            
            project = serializer.validated_data['project']
            version = serializer.validated_data['version']
            content = serializer.validated_data['content']
            
            print(f"项目信息: ID={project.id}, 名称={project.name}")
            print(f"版本信息: ID={version.id}, 版本号={version.version_number}")
            print(f"内容长度: {len(content)}字符")
            
            # 从请求中获取AI模型配置
            ai_model_config = request.data.get('ai_model_config', {})
            ai_model_name = ai_model_config.get('model_name', 'deepseek-r1')
            api_key = ai_model_config.get('api_key')
            api_base = ai_model_config.get('api_base')
            
            print(f"AI模型配置: 模型名称={ai_model_name}, API密钥={'已配置' if api_key else '未配置'}, API Base URL={api_base}")
            
            # 创建生成日志
            generation_log = AIGenerationLog(
                project=project,
                version=version,
                prompt=f"根据需求分析结果生成思维导图",
                generated_cases=0,  # 思维导图不生成用例
                is_success=True,
                created_by=request.data.get('created_by', ''),
                ai_model=ai_model_name
            )
            
            start_time = time.time()
            try:
                # 根据模型名称选择相应的API实现
                if ai_model_name == 'deepseek-r1':
                    ai_api = DeepSeekAPI(api_key=api_key, api_base=api_base)
                else:
                    # 默认使用DeepSeek API
                    ai_api = DeepSeekAPI(api_key=api_key, api_base=api_base)
                    ai_model_name = 'deepseek-r1'  # 回退到默认模型名称
                
                # 生成思维导图的提示词
                project_type = project.get_project_type_display()
                mindmap_prompt = f"""
你是一个专业的需求分析师，请根据以下需求分析结果生成思维导图数据：

需求分析结果：
{content}

请按照以下JSON格式生成思维导图数据，确保JSON格式正确，不要包含其他无关内容：
{{
  "name": "中心主题名称",
  "children": [
    {{
      "name": "一级分支名称",
      "children": [
        {{ "name": "二级分支名称" }},
        {{ "name": "二级分支名称" }}
      ]
    }},
    {{
      "name": "一级分支名称",
      "children": [
        {{ "name": "二级分支名称" }}
      ]
    }}
  ]
}}

注意：这是一个{project_type}类型的项目，请结合项目类型特点组织思维导图内容。
生成的思维导图应该结构清晰，层次分明，准确反映需求的核心内容。
"""
                
                print(f"准备调用AI API生成思维导图，项目类型={project_type}")
                
                # 调用API生成思维导图
                generated_content = ai_api.analyze_requirement(mindmap_prompt, project_type)
                end_time = time.time()
                
                generation_log.generation_time = int(end_time - start_time)
                print(f"AI API调用完成，耗时={end_time - start_time:.2f}秒")
                
                # 解析生成的思维导图数据
                try:
                    print(f"开始解析生成的思维导图内容，长度={len(generated_content)}字符")
                    # 提取JSON部分
                    json_start = generated_content.find('{')
                    json_end = generated_content.rfind('}') + 1
                    print(f"JSON位置: 开始={json_start}, 结束={json_end}")
                    
                    if json_start == -1 or json_end == 0:
                        raise ValueError("生成的内容不是有效的JSON格式")
                    
                    mindmap_data = json.loads(generated_content[json_start:json_end])
                    print(f"JSON解析成功，思维导图数据结构正确")
                    
                    # 保存成功日志
                    generation_log.save()
                    print(f"成功日志保存成功，ID={generation_log.id}")
                    
                    # 返回成功响应
                    return Response({
                        'status': 'success',
                        'message': '思维导图生成成功',
                        'data': {
                            'mindmap_data': mindmap_data,
                            'generation_log_id': generation_log.id
                        }
                    }, status=status.HTTP_200_OK)
                    
                except json.JSONDecodeError as e:
                    error_message = f"思维导图数据格式解析错误: {str(e)}"
                    print(f"JSON解析失败: {error_message}")
                    generation_log.is_success = False
                    generation_log.error_message = error_message
                    generation_log.save()
                    
                    return Response({
                        'status': 'error', 
                        'message': error_message,
                        'error_type': 'json_format_error'
                    }, status=status.HTTP_400_BAD_REQUEST)
                except Exception as e:
                    error_message = f"思维导图数据处理失败: {str(e)}"
                    print(f"数据处理失败: {error_message}")
                    generation_log.is_success = False
                    generation_log.error_message = error_message
                    generation_log.save()
                    
                    return Response({
                        'status': 'error', 
                        'message': error_message
                    }, status=status.HTTP_400_BAD_REQUEST)
                    
            except Exception as e:
                error_message = str(e)
                generation_log.is_success = False
                generation_log.error_message = error_message
                generation_log.save()
                print(f"失败日志保存成功，ID={generation_log.id}")
                
                # 根据错误类型返回不同的error_type
                error_response = {'status': 'error', 'message': error_message}
                
                # API密钥相关错误
                if 'API密钥配置错误' in error_message or 'API key' in error_message or 'api_key' in error_message.lower() or 'your-api-key' in error_message or 'authentication' in error_message.lower():
                    error_response['error_type'] = 'api_key_error'
                    print(f"识别到API密钥错误: {error_message}")
                # 网络相关错误
                elif 'timeout' in error_message.lower() or 'network' in error_message.lower() or '连接' in error_message:
                    error_response['error_type'] = 'network_error'
                    print(f"识别到网络错误: {error_message}")
                else:
                    print(f"其他错误: {error_message}")
                
                return Response(error_response, status=status.HTTP_400_BAD_REQUEST)
        else:
            print(f"请求数据验证失败: {serializer.errors}")
            return Response({
                'status': 'error', 
                'message': '请求参数错误',
                'errors': serializer.errors
            }, status=status.HTTP_400_BAD_REQUEST)
    
    @action(detail=False, methods=['post'], url_path='generate-test-cases')
    def generate_test_cases(self, request):
        """生成测试用例"""
        print("=== 接收测试用例生成请求 ===")
        print(f"请求路径: {request.path}")
        print(f"请求方法: {request.method}")
        
        serializer = GenerateTestCaseSerializer(data=request.data)
        if serializer.is_valid():
            print("请求数据验证通过")
            
            project = serializer.validated_data['project']
            version = serializer.validated_data['version']
            prompt = serializer.validated_data.get('prompt', '')
            template_id = serializer.validated_data.get('template_id')
            requirement_analysis_id = serializer.validated_data.get('requirement_analysis_id')
            
            print(f"项目信息: ID={project.id}, 名称={project.name}")
            print(f"版本信息: ID={version.id}, 版本号={version.version_number}")
            
            # 从请求中获取AI模型配置
            ai_model_config = request.data.get('ai_model_config', {})
            ai_model_name = ai_model_config.get('model_name', 'deepseek-r1')
            api_key = ai_model_config.get('api_key')
            api_base = ai_model_config.get('api_base')
            
            print(f"AI模型配置: 模型名称={ai_model_name}, API密钥={'已配置' if api_key else '未配置'}, API Base URL={api_base}")
            
            # 准备生成用例的内容
            content = prompt
            if requirement_analysis_id:
                try:
                    requirement_analysis = RequirementAnalysis.objects.get(id=requirement_analysis_id)
                    content = requirement_analysis.analysis_result
                    print(f"使用需求分析结果，ID={requirement_analysis_id}")
                except RequirementAnalysis.DoesNotExist:
                    print(f"需求分析不存在，ID={requirement_analysis_id}")
                    return Response({'status': 'error', 'message': '需求分析不存在'}, status=status.HTTP_400_BAD_REQUEST)
            
            # 获取模板（如果有）
            template_content = None
            if template_id:
                try:
                    template = AITemplate.objects.get(id=template_id)
                    template_content = template.content
                    print(f"使用模板，ID={template_id}")
                except AITemplate.DoesNotExist:
                    print(f"模板不存在，ID={template_id}")
                    return Response({'status': 'error', 'message': '模板不存在'}, status=status.HTTP_400_BAD_REQUEST)
            
            # 使用指定的AI模型生成测试用例
            try:
                start_time = time.time()
                # 根据模型名称选择相应的API实现
                if ai_model_name == 'deepseek-r1':
                    ai_api = DeepSeekAPI(api_key=api_key, api_base=api_base)
                else:
                    # 默认使用DeepSeek API
                    ai_api = DeepSeekAPI(api_key=api_key, api_base=api_base)
                    ai_model_name = 'deepseek-r1'  # 回退到默认模型名称
                
                project_type = project.get_project_type_display()
                print(f"准备调用AI API生成测试用例，项目类型={project_type}")
                
                # 调用API生成测试用例
                generated_content = ai_api.generate_test_cases(content, project_type, template_content)
                end_time = time.time()
                
                print(f"AI API调用完成，耗时={end_time - start_time:.2f}秒")
                
                # 解析生成的用例
                try:
                    print(f"开始解析生成的内容，长度={len(generated_content)}字符")
                    # 提取JSON部分
                    json_start = generated_content.find('[')
                    json_end = generated_content.rfind(']') + 1
                    print(f"JSON位置: 开始={json_start}, 结束={json_end}")
                    
                    if json_start == -1 or json_end == 0:
                        raise ValueError("生成的内容不是有效的JSON格式")
                    
                    test_cases_data = json.loads(generated_content[json_start:json_end])
                    print(f"JSON解析成功，包含{len(test_cases_data)}条测试用例")
                except json.JSONDecodeError as json_error:
                    print(f"JSON格式解析错误: {str(json_error)}")
                    return Response({'status': 'error', 'message': f'生成的用例格式无效: {str(json_error)}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
                except Exception as e:
                      print(f"用例解析失败: {type(e).__name__}, {str(e)}")
                      return Response({'status': 'error', 'message': f'用例解析失败: {str(e)}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
                
                # 保存生成日志
                generation_log = AIGenerationLog.objects.create(
                    project=project,
                    version=version,
                    prompt=prompt or template_content or '系统自动生成',
                    generated_cases=len(test_cases_data),
                    is_success=True,
                    created_by=request.data.get('created_by', ''),
                    ai_model=ai_model_name,
                    generation_time=int(end_time - start_time)
                )
                print(f"生成日志保存成功，ID={generation_log.id}")
                
                # 保存生成的用例
                from cases.models import TestCase
                created_cases = []
                print(f"准备保存{len(test_cases_data)}条测试用例")
                
                for idx, case_data in enumerate(test_cases_data):
                    try:
                        # 生成用例ID
                        case_id = f"{project.name}_{version.version_number}_{idx + 1:03d}"
                        # 确保用例ID唯一
                        while TestCase.objects.filter(case_id=case_id).exists():
                            idx += 1
                            case_id = f"{project.name}_{version.version_number}_{idx + 1:03d}"
                        
                        # 创建测试用例
                        test_case = TestCase.objects.create(
                            version=version,
                            case_id=case_id,
                            title=case_data.get('title', f'测试用例{idx + 1}'),
                            description=case_data.get('description', ''),
                            precondition=case_data.get('precondition', ''),
                            steps=case_data.get('steps', ''),
                            expected_result=case_data.get('expected_result', ''),
                            priority=case_data.get('priority', 'medium'),
                            status='draft',  # 初始状态为草稿
                            test_method=case_data.get('test_method', 'other'),
                            created_by=request.data.get('created_by', ''),
                            module=case_data.get('module', '未分类')
                        )
                        
                        # 创建映射关系
                        GeneratedTestCaseMapping.objects.create(
                            generation_log=generation_log,
                            test_case=test_case
                        )
                        
                        created_cases.append(test_case)
                        print(f"已保存测试用例 {idx+1}/{len(test_cases_data)}, ID={test_case.id}")
                    except Exception as case_error:
                        print(f"保存测试用例时出错: {type(case_error).__name__}, {str(case_error)}")
                        # 继续处理下一个用例
                
                # 导出Excel
                from cases.serializers import TestCaseListSerializer
                cases_serializer = TestCaseListSerializer(created_cases, many=True)
                
                print(f"测试用例生成完成，成功保存{len(created_cases)}条")
                
                return Response({
                    'status': 'success',
                    'message': f'成功生成{len(created_cases)}条测试用例',
                    'data': {
                        'cases_count': len(created_cases),
                        'cases': cases_serializer.data,
                        'generation_log_id': generation_log.id
                    }
                })
            except Exception as e:
                # 记录详细错误信息
                import traceback
                print("=== 用例生成异常 ===")
                print(f"异常类型: {type(e).__name__}")
                print(f"异常消息: {str(e)}")
                print("异常堆栈:")
                traceback.print_exc()
                
                # 处理BrokenPipeError异常
                if isinstance(e, BrokenPipeError):
                    print("检测到连接中断错误，客户端可能已断开连接")
                    # 在这种情况下，我们仍然保存日志，但不尝试发送响应，因为客户端可能已断开
                    try:
                        error_message = "客户端连接中断，AI生成过程已取消"
                        generation_log = AIGenerationLog.objects.create(
                            project=project,
                            version=version,
                            prompt=prompt or template_content or '系统自动生成',
                            generated_cases=0,
                            is_success=False,
                            error_message=error_message,
                            created_by=request.data.get('created_by', ''),
                            ai_model=ai_model_name
                        )
                        print(f"连接中断日志保存成功，ID={generation_log.id}")
                    except:
                        pass
                    # 对于BrokenPipeError，我们返回一个空响应，因为客户端已经断开
                    return HttpResponse(status=204)
                
                # 保存失败日志
                error_message = str(e)
                generation_log = AIGenerationLog.objects.create(
                    project=project,
                    version=version,
                    prompt=prompt or template_content or '系统自动生成',
                    generated_cases=0,
                    is_success=False,
                    error_message=error_message,
                    created_by=request.data.get('created_by', ''),
                    ai_model=ai_model_name
                )
                print(f"失败日志保存成功，ID={generation_log.id}")
                
                # 根据错误类型返回不同的error_type
                error_response = {'status': 'error', 'message': error_message}
                
                # API密钥相关错误
                if 'API密钥配置错误' in error_message or 'API key' in error_message or 'api_key' in error_message.lower() or 'your-api-key' in error_message or 'authentication' in error_message.lower():
                    error_response['error_type'] = 'api_key_error'
                    print(f"识别到API密钥错误: {error_message}")
                # JSON格式相关错误
                elif 'JSON格式无效' in error_message or 'JSONDecodeError' in error_message or 'json格式' in error_message.lower() or '格式无效' in error_message:
                    error_response['error_type'] = 'json_format_error'
                    print(f"识别到JSON格式错误: {error_message}")
                # 网络相关错误
                elif 'timeout' in error_message.lower() or 'network' in error_message.lower() or '连接' in error_message:
                    error_response['error_type'] = 'network_error'
                    print(f"识别到网络错误: {error_message}")
                # 数据库相关错误
                elif 'database' in error_message.lower() or 'db' in error_message.lower() or '保存失败' in error_message:
                    error_response['error_type'] = 'database_error'
                    print(f"识别到数据库错误: {error_message}")
                # 其他错误
                else:
                    error_response['error_type'] = 'general_error'
                    print(f"未分类错误: {error_message}")
                
                # 添加原始错误信息以便调试
                error_response['original_error'] = str(e)
                
                return Response(error_response, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        else:
            print(f"请求数据验证失败: {serializer.errors}")
            # 创建响应并添加Connection头
            response = Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
            response['Connection'] = 'keep-alive'
            return response
    
    @action(detail=False, methods=['get'], url_path='export-excel')
    def export_excel(self, request):
        """导出测试用例到Excel"""
        case_ids = request.query_params.getlist('case_ids', [])
        version_id = request.query_params.get('version_id')
        
        # 查询测试用例
        from cases.models import TestCase
        if case_ids:
            queryset = TestCase.objects.filter(id__in=case_ids)
        elif version_id:
            queryset = TestCase.objects.filter(version_id=version_id)
        else:
            return Response({'status': 'error', 'message': '请选择要导出的用例或版本'}, status=status.HTTP_400_BAD_REQUEST)
        
        # 创建Excel文件
        try:
            output = io.BytesIO()
            with pd.ExcelWriter(output, engine='xlwt') as writer:
                # 准备数据
                data = []
                for case in queryset:
                    data.append({
                        '用例ID': case.case_id,
                        '用例标题': case.title,
                        '所属模块': case.module,
                        '用例描述': case.description,
                        '前置条件': case.precondition,
                        '测试步骤': case.steps,
                        '预期结果': case.expected_result,
                        '优先级': case.get_priority_display(),
                        '状态': case.get_status_display(),
                        '用例设计方法': case.get_test_method_display(),
                        '创建时间': case.created_at.strftime('%Y-%m-%d %H:%M:%S'),
                        '创建人': case.created_by or '',
                        '评审人': case.reviewed_by or '',
                        '评审时间': case.reviewed_at.strftime('%Y-%m-%d %H:%M:%S') if case.reviewed_at else '',
                        '是否自动化': '是' if case.is_automated else '否'
                    })
                
                # 创建DataFrame并写入Excel
                df = pd.DataFrame(data)
                df.to_excel(writer, index=False, sheet_name='测试用例')
            
            # 设置响应头
            output.seek(0)
            response = HttpResponse(output.getvalue(), content_type='application/vnd.ms-excel')
            filename = f"测试用例_{datetime.now().strftime('%Y%m%d%H%M%S')}.xls"
            response['Content-Disposition'] = f'attachment; filename="{filename}"'
            return response
        except Exception as e:
            return Response({'status': 'error', 'message': f'导出失败: {str(e)}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

# 创建API路由
from django.urls import path, include
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register(r'ai-templates', AITemplateViewSet)
router.register(r'requirement-analyses', RequirementAnalysisViewSet)
router.register(r'ai-generation-logs', AIGenerationLogViewSet)
router.register(r'generated-case-mappings', GeneratedTestCaseMappingViewSet)
router.register(r'ai-services', AIServiceViewSet, basename='ai-services')

urlpatterns = [
    path('', include(router.urls)),
]
